package site.weiyikai.eventdriven.factory;

import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.core.GenericTypeResolver;
import org.springframework.core.annotation.AnnotationUtils;
import site.weiyikai.eventdriven.core.EventService;
import site.weiyikai.eventdriven.core.EventSubscriber;
import site.weiyikai.eventdriven.core.PredicateBuilder;
import java.util.Optional;
import java.util.Set;
import java.util.function.Predicate;

/**
 *
 * 订阅bean工厂
 * @author 程序员小魏
 * @create 2023/11/09
 */
@Slf4j
public class SubscriberFactoryBean implements InitializingBean, DisposableBean {


    private final Set<EventSubscriber<?>> eventSubscribers;
    private final EventService eventService;

    public SubscriberFactoryBean(Set<EventSubscriber<?>> eventSubscribers, EventService eventService) {
        this.eventSubscribers = eventSubscribers;
        this.eventService = eventService;
    }

    @Override
    public void afterPropertiesSet() {
        Optional.ofNullable(eventSubscribers).ifPresent(eventSubscribers-> eventSubscribers.forEach(eventSubscriber -> {
            Class<?> managerEventClass = GenericTypeResolver.resolveTypeArgument(eventSubscriber.getClass(), EventSubscriber.class);
            SubscribeChannel subscribeChannel = AnnotationUtils.findAnnotation(eventSubscriber.getClass(), SubscribeChannel.class);
            if (subscribeChannel != null) {
                String channel = (String) AnnotationUtils.getValue(subscribeChannel);
                assert managerEventClass != null;
                Predicate<?> eventFilter = PredicateBuilder.isInstanceOf(managerEventClass);
                eventService.subscribe(channel, eventFilter, eventSubscriber);
                log.info("Register subscriber [{}] to channel [{}]", eventSubscriber.getClass().getSimpleName(), channel);
            } else {
                log.warn("Subscriber [{}] not define channel", eventSubscriber.getClass().getSimpleName());
            }
        }));
    }

    @Override
    public void destroy() {
        eventSubscribers.forEach(eventSubscriber -> {
            eventService.unsubscribe(eventSubscriber);
            log.info("unRegister subscriber [{}] ", eventSubscriber.getClass().getSimpleName());
        });
    }
}